# 从flask库中导入需要的模块
# Flask：用于创建Flask应用实例
# request：用于处理客户端发送的请求数据
# jsonify：用于将数据转换为JSON格式的响应
from flask import Flask, request, jsonify
# 从flask_sqlalchemy库导入SQLAlchemy，这是一个ORM工具
# ORM可以让我们用Python类来操作数据库，而不用直接写SQL语句
from flask_sqlalchemy import SQLAlchemy
# 导入pymysql，这是Python操作MySQL的驱动
import pymysql

# 解决MySQL连接问题，将pymysql注册为MySQL的驱动
# 这样SQLAlchemy就能通过它来连接MySQL数据库
pymysql.install_as_MySQLdb()

# 创建一个Flask应用实例
# __name__是Python的特殊变量，表示当前模块的名称
# Flask会根据这个参数来确定应用的根目录
app = Flask(__name__)

# 配置MySQL数据库连接信息
# 格式：mysql://用户名:密码@主机地址:端口/数据库名
# 这里使用的用户名是root，密码是root，数据库名为dbflask
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:root@localhost:3306/dbflask'
# 关闭SQLAlchemy的修改跟踪功能，这样可以提高性能
# 因为这个功能会消耗额外的资源来跟踪对象的修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# 初始化SQLAlchemy，将其与Flask应用关联起来
# db对象将用于后续的数据库操作
db = SQLAlchemy(app)


# 定义User模型，对应数据库中的users表
# 模型类需要继承自db.Model
class User(db.Model):
    # 定义id字段，类型为Integer，作为主键
    # 主键会自动增长，不需要手动指定
    id = db.Column(db.Integer, primary_key=True)
    # 定义username字段，类型为String(80)
    # unique=True表示用户名唯一，nullable=False表示不能为空
    username = db.Column(db.String(80), unique=True, nullable=False)
    # 定义email字段，类型为String(120)
    # 同样设置为唯一且不能为空
    email = db.Column(db.String(120), unique=True, nullable=False)

    # 定义__repr__方法，用于在打印对象时显示友好的信息
    def __repr__(self):
        return f'<User {self.username}>'

    # 定义to_dict方法，将对象转换为字典
    # 这样方便后续使用jsonify转换为JSON响应
    def to_dict(self):
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email
        }


# 创建数据库表（仅需执行一次）
# 使用app.app_context()获取应用上下文
# 因为Flask的很多功能需要在应用上下文中才能使用
with app.app_context():
    # db.create_all()会根据上面定义的模型创建对应的数据库表
    # 如果表已经存在，则不会重复创建
    db.create_all()


# 定义路由：处理创建新用户的请求
# @app.route是Flask的路由装饰器，用于将URL路径与函数关联
# '/users'是URL路径，methods=['POST']表示只接受POST请求
@app.route('/users', methods=['POST'])
def create_user():
    # 从请求中获取JSON数据
    # request.get_json()会解析请求体中的JSON数据并返回一个字典
    data = request.get_json()

    # 验证数据：检查是否提供了用户名和邮箱
    # 如果数据不存在，或者缺少username或email字段，返回错误响应
    if not data or not data.get('username') or not data.get('email'):
        # jsonify用于创建JSON响应，第二个参数是HTTP状态码
        # 400表示请求参数错误
        return jsonify({'error': '缺少用户名或邮箱'}), 400

    # 检查用户名是否已存在
    # User.query.filter_by(username=data['username']).first()会查询数据库中
    # query：查询构建器。filter_by() 方法：用于添加查询条件，按照指定的字段和值去筛选数据，它是一种简单的查询条件构造方式，底层会帮你转化为对应的 SQL 语句中的 WHERE 子句 。
    # username等于data['username']的第一个用户，如果存在则返回该用户对象
    if User.query.filter_by(username=data['username']).first():
        return jsonify({'error': '用户名已存在'}), 400

    # 检查邮箱是否已存在
    if User.query.filter_by(email=data['email']).first():
        return jsonify({'error': '邮箱已存在'}), 400

    # 创建新用户对象
    new_user = User(
        username=data['username'],
        email=data['email']
    )

    # 将新用户添加到数据库会话中
    # db.session是SQLAlchemy中管理数据库操作的 “中间层”，可以理解为一个 “临时操作缓冲区”。它的作用是：
    # 暂时存储所有待执行的数据库操作（新增、修改、删除等）。
    # 统一协调这些操作，确保数据的一致性（例如事务的原子性：要么全部成功，要么全部失败）。
    # 避免频繁与数据库交互（先在内存中缓存操作，最后通过commit()一次性提交到数据库）。
    db.session.add(new_user)
    # 提交会话，将数据保存到数据库中
    db.session.commit()

    # 返回创建的用户信息，201表示资源创建成功
    return jsonify(new_user.to_dict()), 201


# 注释掉的代码：原本用于获取单个用户的路由
# 现在被下面的get_users函数替代，该函数同时处理获取所有用户和单个用户的请求
# @app.route('/users/<int:user_id>', methods=['GET'])
# def get_user(user_id):
#     user = User.query.get_or_404(user_id)
#     return jsonify(user.to_dict())


# 定义路由：处理获取用户的请求（支持获取所有用户或指定ID的用户）
@app.route('/users', methods=['GET'])
def get_users():
    # 从查询参数中获取user_id
    # request.args是一个字典，包含所有的查询参数
    user_id = request.args.get('user_id')
    # 如果提供了user_id参数
    if user_id:
        # 校验user_id是否为数字
        if not user_id.isdigit():
            return jsonify({'error': 'user_id 必须是数字'}), 400
        # 查询指定ID的用户，如果不存在则返回404错误
        # get_or_404方法会在查询不到结果时自动返回404响应
        user = User.query.get_or_404(int(user_id))
        # 返回单个用户信息
        return jsonify(user.to_dict())
    # 如果没有提供user_id参数
    else:
        # 查询所有用户
        users = User.query.all()
        # 将用户列表转换为字典列表并返回
        return jsonify([user.to_dict() for user in users])


# 定义路由：处理更新用户信息的请求
# <int:user_id>是动态URL参数，表示要更新的用户ID
@app.route('/users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
    # 查询指定ID的用户，如果不存在则返回404错误
    user = User.query.get_or_404(user_id)
    # 获取请求中的JSON数据
    data = request.get_json()

    # 如果没有提供任何数据，返回错误响应
    if not data:
        return jsonify({'error': '没有提供更新数据'}), 400

    # 更新字段（如果提供了的话）
    # 检查data中是否包含username字段，如果有则更新
    if 'username' in data:
        user.username = data['username']
    # 检查data中是否包含email字段，如果有则更新
    if 'email' in data:
        user.email = data['email']

    # 提交会话，保存更新到数据库
    db.session.commit()
    # 返回更新后的用户信息
    return jsonify(user.to_dict())


# 定义路由：处理删除用户的请求
@app.route('/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    # 查询指定ID的用户，如果不存在则返回404错误
    user = User.query.get_or_404(user_id)
    # 将用户从数据库会话中删除
    db.session.delete(user)
    # 提交会话，执行删除操作
    db.session.commit()
    # 返回删除成功的消息
    return jsonify({'message': '用户已成功删除'}), 200


# 如果当前模块是主模块（即直接运行该脚本）
if __name__ == '__main__':
    # 启动Flask应用的开发服务器
    # debug=True表示开启调试模式，代码修改后会自动重启服务器
    # 默认情况下，服务器运行在http://127.0.0.1:5000/
    # app.run(debug=True)
    app.run(host='0.0.0.0', port=5000, debug=True)
